﻿using HardcoreGame.Common.CustomSets;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.Audio;
using Terraria.DataStructures;
using Terraria.ModLoader;

namespace HardcoreGame.Content.Items.Weapons.Ranged.DoubleGun
{
    public abstract class BaseDoubleGun : ModItem
    {
        public abstract int MaxBullets { get; }
        public abstract int ProjectileType1 { get; }
        public abstract int ProjectileType2 { get; }
        public abstract SoundStyle ReloadSound { get; }
        public DoubleGunAmmo Ammo { get; private set; }
        public int Rampage { get; protected set; }

        public override void SetStaticDefaults()
        {
            CustomItemSets.DoubleGun[Type] = true;
        }
        public override bool CanShoot(Player player)
        {
            if (player.ownedProjectileCounts[ProjectileType1] > 0 ||
                player.ownedProjectileCounts[ProjectileType2] > 0)
                return false;

            if (player.altFunctionUse == 2)
            {
                if (player.itemAnimation == player.itemAnimationMax)
                    Reload(player);
                return false;
            }

            return base.CanShoot(player);
        }

        public override bool AltFunctionUse(Player player) => true;

        public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source,
                                 Vector2 position, Vector2 velocity, int type, int damage, float knockback)
        {
            Ammo ??= new DoubleGunAmmo(MaxBullets);

            if (!Ammo.HasAmmo)
            {
                Reload(player);
                return false;
            }

            HandleShooting(player, source, position, velocity, damage, knockback);
            return false;
        }

        protected virtual void HandleShooting(Player player, EntitySource_ItemUse_WithAmmo source,
                                            Vector2 position, Vector2 velocity, int damage, float knockback)
        {
            if (Rampage > 0)
            {
                Ammo.EnsureValidGun();
                FireGuns(player, source, position, velocity, damage, knockback);
                Ammo.ConsumeBullet();
            }
            else
            {
                if (Main.rand.NextBool(2))
                    Ammo.SwitchGun();

                Ammo.EnsureValidGun();
                FireGuns(player, source, position, velocity, damage, knockback);
                Ammo.ConsumeBullet();
            }
        }

        protected void FireGuns(Player player, IEntitySource source, Vector2 position,
                              Vector2 velocity, int damage, float knockback)
        {
            Projectile.NewProjectile(source, position, velocity, ProjectileType2,
                damage, knockback, player.whoAmI, Ammo.IsLiving ? 1 : 0);

            Projectile.NewProjectile(source, position, velocity, ProjectileType1,
                damage, knockback, player.whoAmI, Ammo.IsLiving ? 0 : 1);
        }

        protected virtual void Reload(Player player)
        {
            Ammo?.Reload();
            Rampage = 0;
            SoundEngine.PlaySound(ReloadSound, player.position);
        }

        public override void UpdateInventory(Player player)
        {
            if (Rampage > 0)
                Rampage--;
        }

        public override void HoldItem(Player player)
        {
            Item.useTime = Rampage > 0 ? 5 : 20;
            Item.useAnimation = Rampage > 0 ? 5 : 20;
        }
    }

    public class DoubleGunAmmo(int maxBullet)
    {
        public int MaxBullet { get; } = maxBullet;
        public int[] CurrentBullets { get; private set; } = [maxBullet, maxBullet];
        public bool IsLiving { get; set; }

        public void Reload() => CurrentBullets = [MaxBullet, MaxBullet];

        public void ConsumeBullet()
        {
            if (IsLiving) CurrentBullets[0]--;
            else CurrentBullets[1]--;
            IsLiving = !IsLiving;
        }

        public bool HasAmmo => CurrentBullets[0] > 0 || CurrentBullets[1] > 0;

        public void SwitchGun() => IsLiving = !IsLiving;

        public void EnsureValidGun()
        {
            if (IsLiving && CurrentBullets[0] <= 0) IsLiving = false;
            else if (!IsLiving && CurrentBullets[1] <= 0) IsLiving = true;
        }
    }
}